﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using ttbit.core;
using ttbit.math;

namespace ttbit.form.impl
{
    public class RenderTargetMain : IRenderTarget
    {
        public bool FlipY => true;
        public ColorF ClearColor
        {
            get;
            set;
        }
        public Vector2 LookAt
        {
            get;
            set;
        }
        public float Scale
        {
            get;
            set;
        } = 1.0f;

        public TextureFormat format => TextureFormat.RGBA32;

        public int width
        {
            get;
            set;
        }

        public int height
        {
            get;
            set;
        }

        public bool isStatic => true;

        public uint ID => 0;


        public void Dispose()
        {
            throw new NotImplementedException();
        }

        public void Begin()
        {
            Graphics.GL.BindFrameBuffer(0);
            Graphics.GL.Viewport(0, 0, width, height);
            Graphics.GL.ClearColor(ClearColor.R, ClearColor.G, ClearColor.B, ClearColor.A);
            Graphics.GL.Clear(IGL.ClearFlag.ColorBufferBit);
        }

        public void End()
        {
        }
    }

    internal class Graphics : IGraphic
    {
        public Graphics()
        {
            InitWhiteTex();

            CoreResource.Init();
            //_batcher = new Renderer_Batcher(this);
        }

        public IBatcher CreateRenderer_Batcher(IRenderTarget target)
        {
            return new Renderer_Batcher(this, target);
        }
        public void Render()
        {
            OnPreRender?.Invoke();

            //尝试执行截屏任务
            if (queueShotTask.TryDequeue(out var q))
            {
                var data = new byte[q.target.width * q.target.height * (q.target.format == TextureFormat.RGBA32 ? 4 : 1)];
                q.target.nativeTex.ReadPixel(data);
                q.onReadPixel(q.target.format, q.target.width, q.target.height,data);
            }

            //最终输出
            MainScreen.Begin();
            if (OnRender != null)
            {
                //_batcher.Target = MainTarget;
                //Batcher.BeginDraw();
                OnRender();
                //Batcher.EndDraw();
            }
            MainScreen.End();
        }

        public void Resize(int w, int h)
        {
            MainTarget.width = w;
            MainTarget.height = h;

         
        }
        public static ttbit.IGL.ITTGL GL = new ttbit.Impl.GLWin();
        public ITexture TextureWhite
        {
            get;
            private set;
        }
        void InitWhiteTex()
        {
            byte[] data = new byte[4 * 4 * 4];
            for (var i = 0; i < data.Length; i++)
                data[i] = 255;
            TextureWhite = CreateStaticTexture(4, 4, TextureFormat.RGBA32,  data);
        }

        public IRenderTarget MainScreen => MainTarget;
        RenderTargetMain MainTarget = new RenderTargetMain();
        List<IRenderTarget> renderTargets = new List<IRenderTarget>();

        public event Action OnRender;
        //public event Action<IRenderTarget> OnRenderTarget;
        public event Action OnPreRender;



        public void ApplyTexture(ITexture texture, bool TurnToStatic = false)
        {
            var tex = texture as FormTexture;
            if (tex.isStatic)
                throw new Exception("can not parse state texture");

            tex.nativeTex.UploadData((ushort)tex.width, (ushort)tex.height, tex.nativeTex.Format, tex.pixelbuf);
            if (TurnToStatic)
            {
                tex.pixelbuf = null;
            }
        }

        public ITexture CreateDynamicTexture(int w, int h, TextureFormat format)
        {
            var tex = new FormTexture();
            tex.nativeTex = new Texture((ushort)w, (ushort)h, format == TextureFormat.RGBA32 ? IGL.TextureType.RGBA_32 : IGL.TextureType.R_U8);
            tex.pixelbuf = new byte[w * h * (format == TextureFormat.RGBA32 ? 4 : 1)];
            return tex;
        }

        public void UploadTexture(ITexture tex, int x, int y, int w, int h, byte[] data)
        {
            var texi = tex as FormTexture;
            for (var sy = 0; sy < h; sy++)
            {
                for (var sx = 0; sx < w; sx++)
                {
                    var srci = sy * w + sx;
                    var desti = (sy + y) * tex.width + (sx + x);
                    if (((sy + y) < tex.height) && ((sx + x) < tex.width))
                    {
                        if (tex.format == TextureFormat.RGBA32)
                        {
                            texi.pixelbuf[desti * 4 + 0] = data[srci * 4 + 0];
                            texi.pixelbuf[desti * 4 + 1] = data[srci * 4 + 1];
                            texi.pixelbuf[desti * 4 + 2] = data[srci * 4 + 2];
                            texi.pixelbuf[desti * 4 + 3] = data[srci * 4 + 3];
                        }
                        else
                        {
                            texi.pixelbuf[desti] = data[srci];
                        }
                    }
                }
            }
        }
        public IRenderTarget CreateRenderTarget(int w, int h, TextureFormat format)
        {
            return new FormRenderTexture() { nativeTex = new RenderTexture((ushort)w, (ushort)h, format == TextureFormat.RGBA32 ? IGL.TextureType.RGBA_32 : IGL.TextureType.R_U8) };
        }

        public ITexture CreateStaticTexture(int w, int h, TextureFormat format, byte[] data)
        {
            var tex = new FormTexture();
            tex.nativeTex = new Texture((ushort)w, (ushort)h, format == TextureFormat.RGBA32 ? IGL.TextureType.RGBA_32 : IGL.TextureType.R_U8);
            tex.nativeTex.UploadData((ushort)w, (ushort)h, format == TextureFormat.RGBA32 ? IGL.TextureType.RGBA_32 : IGL.TextureType.R_U8, data);
            tex.pixelbuf = null;
            return tex;
        }


        class SnapShotTask
        {
            public FormRenderTexture target;
            public Action<TextureFormat, int, int, byte[]> onReadPixel;
        }
        Queue<SnapShotTask> queueShotTask = new Queue<SnapShotTask>();
        public void ReadPixel(IRenderTarget target, Action<TextureFormat, int, int, byte[]> onReadBack)
        {
            SnapShotTask task = new SnapShotTask();
            task.target = target as FormRenderTexture;
            task.onReadPixel = onReadBack;
            queueShotTask.Enqueue(task);

        }

    }
}
